using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Speedball2 {
  public class Game {
    //private static byte [] _diskAtari;
    public Match _match;

    public static Font Font = new Font (FontFamily.GenericSansSerif, 9, GraphicsUnit.Pixel);
    public static bool _debug = false;

    public static byte [] _bytesAtariDisk = Resource.Atari_Disk;
    public static byte [] _bytesAtariIntro = Resource.Atari_Intro;
    public static byte [] _bytesAmigaDisk = Resource.Amiga_Disk;
    public static byte [] _bytesAmigaMatch = Resource.Amiga_Match;
    public static byte [] _bytesAmigaIntro = Resource.Amiga_Intro;

    public Game () {
      Random random = new Random ();
      myRandom = new MyRandom (random.Next (), random.Next ()); // Demo3
      if (_debug)
        //myRandom = new MyRandom (0x628DB064, 0xFCD1540A); // Demo1
        //myRandom = new MyRandom (0x68CDFD06, 0xFF83E75E); // Demo2
        //myRandom = new MyRandom (0x7D7146C4, 0xFD553F3E); // Demo3
        myRandom = new MyRandom (0x62D942D0, 0x10519DBE); // Demo4

      //Random.Next ();
      //Random.Next ();

      //return;


      //BankManager.Init (_paletteMenu, _paletteManager, _paletteMatch, _paletteMatchBlue);
      //TextManager.Init ();


      // TEAM PLAYERS
      Player [] playersTeam1 = new Player [9];
      for (int i = 0; i < 9; i++)
        playersTeam1 [i] = new Player (Game.AtariDisk, Game.AtariRamToDisk (0x4BB2 + i * Player.Size), i, true);
      Player [] playersTeam2 = new Player [9];
      for (int i = 0; i < 9; i++)
        playersTeam2 [i] = new Player (Game.AtariDisk, Game.AtariRamToDisk (0x4FB4 + i * Player.Size), i, false);

      // TEAM ATTRIBUTES
      Attributes [] attributesTeam1 = new Attributes [12];
      for (int i = 0; i < 12; i++)
        attributesTeam1 [i] = new Attributes (Game.AtariDisk, Game.AtariRamToDisk (0x40A6 + i * Attributes.Size));
      Attributes [] attributesTeam2 = new Attributes [12];
      for (int i = 0; i < 12; i++)
        attributesTeam2 [i] = new Attributes (Game.AtariDisk, Game.AtariRamToDisk (0x412A + i * Attributes.Size));
      Attributes attributesTemp = new Attributes (Game.AtariDisk, Game.AtariRamToDisk (0x41AE));

      // TEAMS
      Team [] teams = new Team [16];
      for (int i = 0; i < 16; i++)
        teams [i] = new Team (Game.AtariDisk, Game.AtariRamToDisk (0x63D4 + i * Team.Size));
      Team teamPlayer2 = new Team (Game.AtariDisk, Game.AtariRamToDisk (0x6394));

      // PERSONS
      Person [] personsTeam1 = new Person [12];
      for (int i = 0; i < 12; i++)
        personsTeam1 [i] = new Person (Game.AtariDisk, Game.AtariRamToDisk (0x421A + i * Person.Size));
      Person [] personsTeam2 = new Person [12];
      for (int i = 0; i < 12; i++)
        personsTeam2 [i] = new Person (Game.AtariDisk, Game.AtariRamToDisk (0x4300 + i * Person.Size));
      Person personTemp = new Person (Game.AtariDisk, Game.AtariRamToDisk (0x42C2));

      // MARKET ATTRIBUTES
      Attributes [] attributesMarket = new Attributes [18];
      for (int i = 0; i < 18; i++)
        attributesMarket [i] = new Attributes (Game.AtariDisk, Game.AtariRamToDisk (0x43D8 + i * Attributes.Size));

      // MARKET STARS
      Star [] starsMarket = new Star [18];
      for (int i = 0; i < 18; i++)
        starsMarket [i] = new Star (Game.AtariDisk, Game.AtariRamToDisk (0x449E + i * Star.Size));

      GameTypeEnum gameType = GameTypeEnum.Knockout;
      if (_debug)
        gameType = GameTypeEnum.Knockout;

      MatchParam matchParam = new MatchParam ();
      matchParam.gameType = gameType;
      //matchParam.palette = _paletteMatch;
      matchParam.playersTeam1 = playersTeam1;
      matchParam.playersTeam2 = playersTeam2;
      matchParam.attributesMarket = attributesMarket;
      matchParam.attributesTeam1 = attributesTeam1;
      matchParam.attributesTeam2 = attributesTeam2;
      matchParam.attributesTemp = attributesTemp;
      matchParam.personsTeam1 = personsTeam1;
      matchParam.personsTeam2 = personsTeam2;
      matchParam.personTemp = personTemp;

      matchParam.coinsCredits = -1;
      matchParam.legDuration = -1;
      matchParam.creditsEarnablePerMatch = -1;
      matchParam.maxCreditsEarnableTeam1 = -1;
      matchParam.maxCreditsEarnableTeam2 = -1;
      matchParam.initialDirTeam1 = -1;
      matchParam.team1 = null;
      matchParam.team2 = null;

      matchParam.creditsTeam1 = -1;
      matchParam.creditsTeam2 = -1;
      matchParam.minCreditsEarnable = -1;

      matchParam.isComputerPlayer1 = false;
      matchParam.isComputerPlayer2 = false;

      // on load value
      matchParam.coinsCredits = 100;
      matchParam.legDuration = 90;
      matchParam.creditsEarnablePerMatch = 0;
      matchParam.maxCreditsEarnableTeam1 = 0;
      matchParam.maxCreditsEarnableTeam2 = 0;
      matchParam.initialDirTeam1 = 0;
      matchParam.team1 = teams [0];
      matchParam.team2 = teams [1];

      // main menu init
      matchParam.creditsTeam1 = 1100;
      matchParam.creditsTeam2 = 1100;
      matchParam.minCreditsEarnable = 0;

      // two player game menu
      if (gameType == GameTypeEnum.TwoPlayers) {
        sub_B5BA_InitTeams (teamPlayer2, teams);

        Text textFullName = teams [0]._textFullName;
        Text textShortName = teams [0]._textShortName;
        teams [0]._textFullName = TextPanel.GetText (TextEnum.Player1Full);
        teams [0]._textShortName = TextPanel.GetText (TextEnum.Player1Short);

        matchParam.creditsEarnablePerMatch = 2000;
        matchParam.maxCreditsEarnableTeam1 = matchParam.creditsEarnablePerMatch;
        matchParam.maxCreditsEarnableTeam2 = matchParam.creditsEarnablePerMatch;
        // todo: choose nb matchs
        matchParam.team1 = teams [0];
        matchParam.team2 = teamPlayer2;
        InitAllAttributesWithValue (attributesTeam1, 170);
        InitAllAttributesWithValue (attributesTeam2, 170);
        matchParam.isComputerPlayer1 = false;
        matchParam.isComputerPlayer2 = false;
        // todo: init nb matchs won
        matchParam.initialDirTeam1 = 0;
      }

      // one player game menu
      else if ((gameType == GameTypeEnum.Knockout) ||
               (gameType == GameTypeEnum.League) ||
               (gameType == GameTypeEnum.Cup) ||
               (gameType == GameTypeEnum.Practice)) {
        InitAllAttributesWithValue (attributesTeam1, 100);
        InitAllAttributesWithValue (attributesTeam2, 100);
        matchParam.isComputerPlayer1 = false;
        matchParam.isComputerPlayer2 = true;

        if (gameType == GameTypeEnum.Practice) {
          matchParam.team1 = teams [0];
          foreach (Player player in playersTeam2)
            player.Bit7_IsInvisible = true;
          matchParam.isComputerPlayer2 = false;
        }
        else if (gameType == GameTypeEnum.Knockout) {
          sub_B5BA_InitTeams (teamPlayer2, teams);
          matchParam.creditsEarnablePerMatch = 1100;
          matchParam.maxCreditsEarnableTeam1 = 1100;
          matchParam.maxCreditsEarnableTeam2 = 1100;
          matchParam.team1 = teams [0];
          matchParam.team2 = teams [1];

          // for WIP, player 1 is computer until moved
          // for WIP, player 2 is a random team
          //matchParam.isComputerPlayer1 = true;
          //if (_debug) {
          matchParam.isComputerPlayer1 = true;
          matchParam.isComputerPlayer2 = true;
          do {
            matchParam.team1 = teams [random.Next (0, 16)]; // 15 for demo 3
            matchParam.team2 = teams [random.Next (0, 16)]; // 15 for demo 3
          } while (matchParam.team1 == matchParam.team2);
          //matchParam.team1 = teams [0];
          //matchParam.team2 = teams [15];
          matchParam.team1.sub_903E_CopyAttributesFromGroups (attributesTeam1);
          //}

          matchParam.team2.sub_903E_CopyAttributesFromGroups (attributesTeam2);
          matchParam.initialDirTeam1 = 0;
        }
        else if (gameType == GameTypeEnum.League) {
          matchParam.creditsEarnablePerMatch = 550;
          matchParam.maxCreditsEarnableTeam1 = matchParam.creditsEarnablePerMatch;
          matchParam.maxCreditsEarnableTeam2 = matchParam.creditsEarnablePerMatch;
          sub_B5BA_InitTeams (teamPlayer2, teams);
          matchParam.initialDirTeam1 = 0;
          // todo: manager

          // manager
          matchParam.minCreditsEarnable = 300;
          throw new Exception ();
        }
        else if (gameType == GameTypeEnum.Cup) {
          matchParam.coinsCredits = 200;
          matchParam.creditsEarnablePerMatch = 2000;
          matchParam.maxCreditsEarnableTeam1 = matchParam.creditsEarnablePerMatch;
          matchParam.maxCreditsEarnableTeam2 = matchParam.creditsEarnablePerMatch;
          // todo sub_8650
          matchParam.creditsTeam1 = 2000;
          matchParam.creditsTeam2 = 2000;
          throw new Exception ();
        }
      }

      // demo game menu
      else if (gameType == GameTypeEnum.Demo) {
        matchParam.isComputerPlayer1 = true;
        matchParam.isComputerPlayer2 = true;
        matchParam.legDuration = 20;
        matchParam.team1 = teams [14];
        matchParam.team2 = teams [13];
        matchParam.team1.sub_903E_CopyAttributesFromGroups (attributesTeam1);
        matchParam.team2.sub_903E_CopyAttributesFromGroups (attributesTeam2);
      }
      else
        throw new Exception ();
      _match = new Match (matchParam);
    }

    private void sub_B5BA_InitTeams (Team teamPlayer2, Team [] teams) {
      teamPlayer2.Init ();
      foreach (Team team in teams)
        team.Init ();
    }

    private void InitAllAttributesWithValue (Attributes [] attributesList, int value) {
      for (int i = 0; i < 12; i++) {
        Attributes attributes = attributesList [i];
        attributes._agr = value;
        attributes._att = value;
        attributes._def = value;
        attributes._spd = value;
        attributes._thr = value;
        attributes._pow = value;
        attributes._sta = value;
        attributes._int = value;
      }
    }

    public bool Update () {
      bool isMatchOver = _match.Iterate ();
      return (isMatchOver);
    }

    //public void Draw (Graphics g) {
    //  bool isMatchOver = _match.Iterate ();
    //  //g.DrawImage (_match.Screen, 0, 0);
    //}

    public Bitmap Screen {
      get {
        return (_match.Screen);
      }
    }

    public static int AtariRamToDisk (int ramOffset) {
      // Atari: EB8
      // Amiga: 25CC
      // Atari -> Amiga: +1714
      //
      // Atari: 6818
      // Amiga: 7F2C
      return (ramOffset - 0x400 + 0x4D600);
    }

    public static int AtariDiskToRam (int diskOffset) {
      return (diskOffset - 0x4D600 + 0x400);
    }

    public static byte [] AtariDisk {
      get {
        return (_bytesAtariDisk);
      }
    }

    public static byte [] AtariIntro {
      get {
        return (_bytesAtariIntro);
      }
    }

    public static byte [] AmigaDisk {
      get {
        return (_bytesAmigaDisk);
      }
    }

    public static byte [] AmigaMatch {
      get {
        return (_bytesAmigaMatch);
      }
    }

    public static byte [] AmigaIntro {
      get {
        return (_bytesAmigaIntro);
      }
    }

    //public static Random _random = new Random ();
    //public static int Random (int max) {
    //  return (_random.Next (max + 1));
    //}

    public static MyRandom myRandom = new MyRandom ();
    //public static int Random (int max) {
    //  return (_random.Next (max + 1));
    //}
  }
}
